package ift605.tp2.sectionA.server;

import java.net.InetAddress;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

import udes.ds.rmi.hw.BasicEquation;
import udes.ds.rmi.hw.Constant;
import udes.ds.rmi.hw.Equation;
import udes.ds.rmi.hw.MultiplicativeEquation;
import udes.ds.rmi.hw.PolynomialEquation;
import udes.ds.rmi.hw.UnknownEquationTypeException;

@SuppressWarnings("serial")
public class MyServer extends UnicastRemoteObject implements MyServerPublicInterface{

	protected MyServer() throws RemoteException {
		super();
	}

	public static void main(String[] args) {
		try {
			MyServer server = new MyServer();
			Naming.rebind("MyServer", server);
			
			try
			{
				System.out.println("IP Address : " + InetAddress.getLocalHost().getHostAddress());
			}
			catch( Exception e){}
		} 
		catch (RemoteException e) {e.printStackTrace();}
		catch (MalformedURLException e) {e.printStackTrace();}
	}

	@Override
	public Equation resolveEquation(Equation aEquation) throws UnknownEquationTypeException {
		System.out.println("Before : " + aEquation.getUserReadableString());
		Equation answer = computeDerivative(aEquation);

		answer = cleanEquation(answer);
		System.out.println("After : " + answer.getUserReadableString());
		return answer;
	}
	
	protected Equation cleanEquation(Equation aAnswer)
	{
		if( IsZero(aAnswer))
		{
			return new Constant(0.0);
		}
		
		Equation result = aAnswer;
		if(aAnswer.getClass() == Constant.class)
		{}
		else if(aAnswer.getClass() == BasicEquation.class)
		{}
		else if(aAnswer.getClass() == PolynomialEquation.class)
		{
			Equation firstResult = cleanEquation(((PolynomialEquation)aAnswer).getFirst());
			Equation secondResult = cleanEquation(((PolynomialEquation)aAnswer).getSecond());
			
			boolean isFirstZero = IsZero(firstResult);
			boolean isSecondZero = IsZero(secondResult);
			
			if(isFirstZero && isSecondZero)
			{
				result = new Constant(0);
			}
			else if(isFirstZero)
			{
				result = secondResult;
			}
			else if(isSecondZero)
			{
				result = firstResult;
			}
			else
			{
				result = new PolynomialEquation(firstResult, secondResult);
			}
		}
		else if(aAnswer.getClass() == MultiplicativeEquation.class)
		{

			Equation firstResult = cleanEquation(((MultiplicativeEquation)aAnswer).getFirst());
			Equation secondResult = cleanEquation(((MultiplicativeEquation)aAnswer).getSecond());
			
			boolean isFirstZero = IsZero(firstResult);
			boolean isSecondZero = IsZero(secondResult);
			
			if( isFirstZero || isSecondZero)
			{
				result = new Constant(0);
			}
			else
			{
				result = new MultiplicativeEquation(firstResult, secondResult);
			}
		}
		
		return result;
	}
	
	private boolean IsZero(Equation aAnswer)
	{
		if(aAnswer.getClass() == Constant.class)
		{
			return ((Constant)aAnswer).getValue() == 0.0;
		}
		else if(aAnswer.getClass() == BasicEquation.class)
		{
			return ((BasicEquation)aAnswer).getCoefficient() == 0.0;
		}
		else if(aAnswer.getClass() == PolynomialEquation.class)
		{
			boolean isFirstZero = IsZero(((PolynomialEquation)aAnswer).getFirst());
			boolean isSecondZero = IsZero(((PolynomialEquation)aAnswer).getSecond());
			
			if(isFirstZero && isSecondZero)
			{
				return true;
			}
		}
		else if(aAnswer.getClass() == MultiplicativeEquation.class)
		{
			boolean isFirstZero = IsZero(((MultiplicativeEquation)aAnswer).getFirst());
			boolean isSecondZero = IsZero(((MultiplicativeEquation)aAnswer).getSecond());
			
			if(isFirstZero || isSecondZero)
			{
				return true;
			}
		}
		return false;
	}

	protected Equation computeDerivative(Equation aEquation) throws UnknownEquationTypeException {
		Equation result = new Constant(0);
		if(aEquation.getClass() == Constant.class)
		{
			//Return Constant(0), but it is by default
		}
		else if(aEquation.getClass() == BasicEquation.class)
		{
			BasicEquation casted = (BasicEquation)aEquation;
			if(casted.getExponent() != 1)
			{
				result = new BasicEquation( casted.getCoefficient() * casted.getExponent(), casted.getExponent() - 1);
			}
			else
			{
				result = new Constant( casted.getCoefficient() * casted.getExponent());
			}
		}
		else if(aEquation.getClass() == PolynomialEquation.class)
		{
			PolynomialEquation casted = (PolynomialEquation)aEquation;
			result = new PolynomialEquation( computeDerivative(casted.getFirst()) , computeDerivative(casted.getSecond()));
		}
		else if(aEquation.getClass() == MultiplicativeEquation.class)
		{
			MultiplicativeEquation casted = (MultiplicativeEquation)aEquation;
			result = new PolynomialEquation(  	new MultiplicativeEquation( casted.getFirst() , computeDerivative(casted.getSecond())), 
												new MultiplicativeEquation( computeDerivative(casted.getFirst()) , casted.getSecond()));
		}
		else
		{
			throw new UnknownEquationTypeException("Equation is unknown to server");
		}
		return result;
	}

}
